/*
 * @Author: intellectual-seeker 3336339701@qq.com
 * @Date: 2025-08-07 21:39:01
 * @LastEditors: intellectual-seeker 3336339701@qq.com
 * @LastEditTime: 2025-08-07 23:13:33
 * @FilePath: /code/lesson25/test3/processpool.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include "task.hpp"
#include <sys/wait.h>

//错误码
enum
{
    PipeErr = 1,//创建管道失败
    ArgErr
};

//将程序使用范式打印出来
void Usage(char* process)
{
    cout << "Usage:\n\t" << process << " subprocess_num" << endl;
}

//自定义管道类型："r"管道文件fd，管道链接的子进程pid，管道的名称(channel-num)
class Channel
{
public:
    Channel(int wfd, pid_t subprocess_id, string name)
        :_wfd(wfd), _subprocess_id(subprocess_id), _name(name)
    {}

    int wfd()
    {
        return _wfd;
    }

    const string& name()
    {
        return _name;
    }

    pid_t id()
    {
        return _subprocess_id;
    }

    ~Channel()
    {}

private:
    int _wfd;
    pid_t _subprocess_id;
    string _name;
};

//进程池：子进程数量，与子进程通信的管道
class ProcessPool
{
public:
    ProcessPool(int subprocess_num)
        :_subprocess_num(subprocess_num)
    {}

    //创建子进程与管道
    int CreateProcess(work_t worker)
    {
        vector<int> fds;
        for(int i = 0; i < _subprocess_num; i++)
        {
            //先创建管道
            int pipefd[2];
            int n = pipe(pipefd);
            if(n < 0) return PipeErr;//返回值为-1时，表示创建失败

            //创建子进程
            int fd = fork();//创建失败返回-1

            //child -r
            if(fd == 0)
            {
                //处理子进程多写端bug
                cout << "wfd: ";
                for(int j = 0; j < fds.size(); j++)
                {
                    close(fds[j]);
                    cout << fds[j] << ' ';
                }
                cout << endl;

                close(pipefd[1]);
                dup2(pipefd[0], 0);
                worker(pipefd[0]);

                exit(0);
            }

            sleep(1);

            //parent -w
            close(pipefd[0]);

            //创建子进程对应的管道类，用于之后的通信
            string name = "channel-" + std::to_string(i);
            channels.push_back(Channel(pipefd[1], fd, name));//参数："w"端文件fd，子进程pid，管道名称

            fds.push_back(pipefd[1]);
        }

        return 0;
    }

    //rs轮询调用子进程执行任务
    int NextChannel()
    {
        static int pos = 0;
        int next = pos++;
        pos %= channels.size();

        return next;
    }

    //发送任务码
    void SendTaskCode(int channel, size_t commandcode)
    {
        int wfd = channels[channel].wfd();
        cout << channels[channel].name() << " wfd: " << wfd << " send commandcode is " << commandcode << endl;

        write(wfd, &commandcode, sizeof(commandcode));
    }

    void KillAll()
    {
        for(int i = 0; i < channels.size(); i++)
        {
            close(channels[i].wfd());//关闭父进程写端
            waitpid(channels[i].id(), nullptr, 0);//参数：等待子进程pid，子进程退出码，0：阻塞等待
        }
    }

    ~ProcessPool()
    {}

private:
    int _subprocess_num;
    vector<Channel> channels;
};

void CtrlSubProcess(ProcessPool* processpool_ptr, int cnt)
{
    while(cnt--)
    {
        //向哪个子进程发送，发送几号任务码
        int channel = processpool_ptr->NextChannel();
        size_t commandcode = NextTask();//size_t, int?

        processpool_ptr->SendTaskCode(channel, commandcode);

        sleep(1);
    }
}

int main(int argc, char* argv[])
{
    //使用手册
    if(argc != 2)
        Usage(argv[0]);

    //创建进程池
    int subprocess_num = std::stoi(argv[1]);
    if(subprocess_num < 0) return ArgErr;//进程数不合法

    ProcessPool* processpool_ptr = new ProcessPool(subprocess_num);
    processpool_ptr->CreateProcess(worker);

    //控制子进程
    CtrlSubProcess(processpool_ptr, 5);//执行cnt次任务

    processpool_ptr->KillAll();

    cout << "quit now..." << endl;
    
    delete processpool_ptr;

    return 0;
}